//=============================================================================

#include "../../../../inc/aNet.h"

//=============================================================================

aNet::aNet()
{
  sock = 0;
  sInit = 0;
  totalIn = 0;
  totalOut = 0;
  port = 31356;

  switch(anInit())
  {
    case NET_WSASYSNOTREADY:
    {
      LOG.alWrite("The underlying network subsystem is not ready for network communication.");

      break;
    }
    case NET_WSAVERNOTSUPPORTED:
    {
      LOG.alWrite("The version of Windows Sockets support requested is not provided by this particular Windows Sockets implementation.");

      break;
    }
    case NET_WSAEINPROGRESS:
    {
      LOG.alWrite("A blocking Windows Sockets 1.1 operation is in progress.");

      break;
    }
    case NET_WSAEPROCLIM:
    {
      LOG.alWrite("A limit on the number of tasks supported by the Windows Sockets implementation has been reached.");

      break;
    }
    case NET_WSAEFAULT:
    {
      LOG.alWrite("The sData parameter is not a valid pointer.");

      break;
    }
    default:
    {
      LOG.alWrite("WSA started.");

      break;
    }
  }
}

//=============================================================================

antRet aNet::anInit()
{
  int error = WSAStartup(MAKEWORD(2, 2), &sData);

  switch(error)
  {
    case WSASYSNOTREADY:
    {
      sInit = 0;

      return NET_WSASYSNOTREADY;
    }
    case WSAVERNOTSUPPORTED:
    {
      sInit = 0;

      return NET_WSAVERNOTSUPPORTED;
    }
    case WSAEINPROGRESS:
    {
      sInit = 0;

      return NET_WSAEINPROGRESS;
    }
    case WSAEPROCLIM:
    {
      sInit = 0;

      return NET_WSAEPROCLIM;
    }
    case WSAEFAULT:
    {
      sInit = 0;

      return NET_WSAEFAULT;
    }
    default:
    {
      sInit = 1;

      break;
    }
  }

  if (sData.wVersion != 0x0202)
    return NET_WSABADVERSION;

  anSpawnSocket();

  return NET_DONE;
}

//=============================================================================

antRet aNet::anBindSock()
{
  memset(&addr, 0, sizeof(sockaddr_in));
  
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

  if (bind(sock, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
    return NET_SOCKETBINDERROR;

  return NET_DONE;
}

//=============================================================================

void aNet::anDisconnect()
{
  anShutdownSock();
  anSpawnSocket();
}

//=============================================================================

void aNet::anShowLastError()
{
  int error = WSAGetLastError();

  switch(error)
  {
    case WSAENETDOWN:
    {
      MessageBox(0, L"The network subsystem has failed.", L"Socket error", 0);

      break;
    }
    case WSAEFAULT:
    {
      MessageBox(0, L"The buf parameter is not completely contained in a valid part of the user address space.", L"Socket error", 0);

      break;
    }
    case WSAENOTCONN:
    {
      MessageBox(0, L"The socket is not connected.", L"Socket error", 0);

      break;
    }
    case WSAEINTR:
    {
      MessageBox(0, L"The (blocking) call was canceled through WSACancelBlockingCall.", L"Socket error", 0);

      break;
    }
    case WSAEINPROGRESS:
    {
      MessageBox(0, L"A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.", L"Socket error", 0);

      break;
    }
    case WSAENETRESET:
    {
      MessageBox(0, L"The connection has been broken due to the keep-alive activity detecting a failure while the operation was in progress.", L"Socket error", 0);

      break;
    }
    case WSAENOTSOCK:
    {
      MessageBox(0, L"The descriptor is not a socket.", L"Socket error", 0);

      break;
    }
    case WSAEOPNOTSUPP:
    {
      MessageBox(0, L"MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, OOB data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only send operations.", L"Socket error", 0);

      break;
    }
    case WSAESHUTDOWN:
    {
      MessageBox(0, L"The socket has been shut down; it is not possible to receive on a socket after shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH.", L"Socket error", 0);

      break;
    }
    case WSAEWOULDBLOCK:
    {
      MessageBox(0, L"The socket is marked as nonblocking and the receive operation would block.", L"Socket error", 0);

      break;
    }
    case WSAEMSGSIZE:
    {
      MessageBox(0, L"The message was too large to fit into the specified buffer and was truncated.", L"Socket error", 0);

      break;
    }
    case WSAEINVAL:
    {
      MessageBox(0, L"The socket has not been bound with bind, or an unknown flag was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled or (for byte stream sockets only) len was zero or negative.", L"Socket error", 0);

      break;
    }
    case WSAECONNABORTED:
    {
      MessageBox(0, L"The virtual circuit was terminated due to a time-out or other failure. The application should close the socket as it is no longer usable.", L"Socket error", 0);

      break;
    }
    case WSAETIMEDOUT:
    {
      MessageBox(0, L"The connection has been dropped because of a network failure or because the peer system failed to respond.", L"Socket error", 0);

      break;
    }
    case WSAECONNRESET:
    {
      MessageBox(0, L"The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket as it is no longer usable. On a UPD-datagram socket this error would indicate that a previous send operation resulted in an ICMP \"Port Unreachable\" message.", L"Socket error", 0);

      break;
    }

    default:
    {
      break;
    }
  }
}

//=============================================================================

void aNet::anDeInit()
{
  if (sInit)
  {
    anShutdownSock();

    LOG.alWrite(aString().asAcceptWithParams("\nOut: %d bytes.\nIn: %d bytes.", totalOut, totalIn));

    if (!WSACleanup())
      LOG.alWrite("WSA getted down.");
  }
}

//=============================================================================

aNet::~aNet()
{
  aItem<aTransmission<aNet>*>* tmpItem = inTrans.alGetFirstItem();

  while(tmpItem)
  {
    //if (tmpItem->data->handle)
    //{
      DWORD code;

      if (GetExitCodeThread(tmpItem->data->handle, &code))
      {
        TerminateProcess(tmpItem->data->handle, code);
        CloseHandle(tmpItem->data->handle);
      }
    //}

    delete tmpItem->data;

    tmpItem = tmpItem->next;
  }
  anDeInit();
}

//=============================================================================
